//
//  NSObject+propertyWithDict.m
//  runtime功能练习
//
//  Created by 岳云石 on 2017/2/1.
//  Copyright © 2017年 岳云石. All rights reserved.
//

/*
 Objective-C运行时定义了几种重要的类型。
 Class：定义Objective-C类
 Ivar：定义对象的实例变量，包括类型和名字。
 Protocol：定义正式协议。
 objc_property_t：定义属性。叫这个名字可能是为了防止和Objective-C 1.0中的用户类型冲突，那时候还没有属性。
 Method：定义对象方法或类方法。这个类型提供了方法的名字（就是**选择器**）、参数数量和类型，以及返回值（这些信息合起来称为方法的**签名**），还有一个指向代码的函数指针（也就是方法的**实现**）。
 SEL：定义选择器。选择器是方法名的唯一标识符。
 IMP：定义方法实现。这只是一个指向某个函数的指针，该函数接受一个对象、一个选择器和一个可变长参数列表（varargs），返回一个对象
 */

#import "NSObject+propertyWithDict.h"
#import <objc/message.h>
@implementation NSObject (propertyWithDict)

+ (instancetype)configPropertyWithDict:(NSDictionary *)dict{
    //创建实例变量
    id model = [[self alloc] init];
    
    //获取成员变量 列表
    unsigned int count;
    Ivar *ivarList = class_copyIvarList(self, &count);
    
    //遍历成员变量列表 从字典中取到value赋值
    for (int i = 0; i<count; i++) {
        //获取实例变量
        Ivar property = ivarList[i];
        //获取实例变量的名字 是带下划线的 所以要去掉下划线 _name->name
        NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(property)];
        propertyName = [propertyName substringFromIndex:1];
        
        //根据示例变量名字作为key 从字典中获取value
        id value = [dict objectForKey:propertyName];
        
        //成员变量类型
        NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(property)];
        NSLog(@"type = %@",type);
        if ([model respondsToSelector:@selector(changePropertyName)]) {
            //更换变量名字
            NSString *oriPropertyName = [model changePropertyName][propertyName];
            if (oriPropertyName) {
                value = [dict objectForKey:oriPropertyName];
            }
        }
        
        
        if ([value isKindOfClass:[NSArray class]]) {
            type = [self handleTypeString:type];
            //如果是字典套数组
            if ([model respondsToSelector:@selector(listContentModelType)]) {
                NSString *contenModelType = [model listContentModelType][propertyName];
                NSMutableArray *array = [NSMutableArray array];
                
                for (NSDictionary *objcDic in value) {
                    Class class = NSClassFromString(contenModelType);
                    [array addObject:[class configPropertyWithDict:objcDic]];
                }
                
                value = array;
            }
        }
        
        
        if ([value isKindOfClass:[NSDictionary class]]&&![type containsString:@"NS"]) {
            //如果是 字典嵌套字典 需要将字典转化成另一种模型
            type = [self handleTypeString:type];
            Class class = NSClassFromString(type);
            value = [class configPropertyWithDict:value];
        }
        
        if (value) {
            [model setValue:value forKey:propertyName];
        }
    }
    
    return model;
}

/*
 @"@\"NSString\"" -> @"NSString"
 */
#pragma mark -- private
+ (NSString *)handleTypeString:(NSString *)typeStr{
    NSRange range = [typeStr rangeOfString:@"\""];
    typeStr = [typeStr substringFromIndex:range.location + range.length];
    range = [typeStr rangeOfString:@"\""];
    typeStr = [typeStr substringToIndex:range.location];
    return typeStr;
}

@end
